#!BPY

""" Registration info for Blender menus:
Name: 'OGRE (.mesh.xml)...'
Blender: 236
Group: 'Import'
Tip: 'Import an Ogre-Mesh (.mesh.xml) file.'
"""

'''
2015-3-7
修改导出的动画多一 frame的bug


2015-2-5  支持批量导入一个文件夹 某个 模型 所有的 动画 导出为 fbx模型
[已知BUG: ratman 和 主城第一个npc 的idle 动画导出存在旋转问题， ratman的背包的旋转方向反了，npc的手臂旋转方向反了]

注意::下面 代码 函数 fileselection_callback 使用了macos 上面的file 命令用于 识别文件格式 是否是UTF-16, 如果在windows上面使用需要 替换为windows命令，或者保证 转化生成的xml 文件为UTF-8 编码去掉文件编码检测也可以
测试::测试了火炬之光 1中的 media/models/warrior/player.mesh 战士 主角的模型 动画导出

0: 将脚本 放到 blender的插件目录中
1：打开一个空场景 去掉 场景中 所有物体 和 相机 以及其它任何东西
2：file import ogre  打开某个目录的 mesh文件
3：导入后 将会 自动生成 这个 模型的 所有动画的 fbx 在 模型目录下面

'''
bl_info = {
    "name": "ogre mesh import",
    "author": "liyonghelpme",
    "version": (0, 1, 6),
    "blender": (2, 70, 0),
    "location": "File > Import > ogre (.mesh)",
    "description": "import ogre mesh file",
    "warning": "",
    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
                "Scripts/Nodes/Nodes_Efficiency_Tools",
    "category": "Import-Export",
}

__version__ = "1.2.3"

import logging
handle = logging.FileHandler("/Users/liyong/blender.log")
logger = logging.getLogger()
logger.addHandler(handle)
logger.setLevel(logging.INFO)

import bpy
import glob
import os
import re
import xml.sax
import xml.sax.handler

import bmesh
import mathutils
from mathutils import Vector
from mathutils import Matrix
import codecs

# determines the verbosity of loggin.
#   0 - no logging (fatal errors are still printed)
#   1 - standard logging
#   2 - verbose logging
#   3 - debug level. really boring (stuff like vertex data and verbatim lines)
IMPORT_LOG_LEVEL = 1

IMPORT_SCALE_FACTOR = 1
#IMPORT_OGREXMLCONVERTER = "d:\stuff\Torchlight_modding\orge_tools\OgreXmlConverter.exe"
IMPORT_OGREXMLCONVERTER = "/Users/liyong/Downloads/OgreCommandLineToolsMac_1.8.0/OgreXMLConverter"
#IMPORT_OGREXMLCONVERTER = "F:\\Projekte\\rastullah\checkout\\rl\\branches\python\dependencies\ogre\Tools\Common\\bin\\release\\OgreXmlConverter.exe"


def log(msg):
    logger.info(msg)

    #if IMPORT_LOG_LEVEL >= 1: print(msg)

def vlog(msg):
    log(msg)

    #if IMPORT_LOG_LEVEL >= 2: print(msg)

def dlog(msg):
    log(msg)
    #if IMPORT_LOG_LEVEL >= 3: print(msg)

'''
存放Mesh.xml 中读取的三角面片数据
'''
class Mesh:
    def __init__(self):
        self.submeshes = []
        self.vertices = []
        self.vertexcolours = []
        self.normals = []
        self.uvs = []
        self.indextype = ""
        self.materialname = ""
        self.sharedvertices = 0

        self.vertexGroup = {}


'''
OGRE 支持共享顶点和 子面片
一个模型可以：
    只有一个Mesh 使用 sharedvertices
    多个子Mesh 每个子Mesh 有自己的顶点和面
'''
class Submesh:
    def __init__(self):
        self.vertices = []
        self.vertexcolours = []
        self.normals = []
        self.faces = []
        self.uvs = []
        self.indextype = ""
        self.materialname = ""
        self.sharedvertices = 0

        self.vertexGroup = {}

'''
OGRE 的材质
    diffuse
    ambient
    specular
    Texture
'''
class Material:
    def __init__(self, name):
        self.name = name
        self.texname = 0
        self.diffuse = (1.0, 1.0, 1.0, 1.0)
        self.ambient = (1.0, 1.0, 1.0, 1.0)
        self.specular = (0.0, 0.0, 0.0, 0.0)
        self.blenderimage = 0
        self.loading_failed = 0
        self.matFileCon = ''
        self.oldTexName = ''

    def getTexture(self):
        log("texname is "+str(self.texname))
        if self.texname == 0:
            return None
        if self.blenderimage == 0 and not self.loading_failed:
            try:
                #f = file(self.texname, 'r')

                #f.close()
                #self.blenderimage = Blender.Image.Load(self.texname)
                if self.texname == 0:
                    return None

                if not os.path.exists(self.texname):
                    self.texname = self.texname.replace('.png', '.dds')
                

                if os.path.exists(self.texname):
                    self.blenderimage = bpy.data.images.load(self.texname)

            except IOError as err:
                errmsg = "Couldn't open %s #%s" \
                        % (self.texname, err)
                log(errmsg)
                self.loading_failed = 1;
             
        return self.blenderimage


'''
读取Mesh.xml 文件
    读取共享Mesh
    读取SubMesh

    可以多个SubMesh 共享一个顶点集合
    也可以每个SubMesh 有自己的顶点集合

    读取基本的骨架文件名称
'''
class OgreMeshSaxHandler(xml.sax.handler.ContentHandler):
    
    global IMPORT_SCALE_FACTOR
    
    def __init__(self):
        self.mesh = 0
        self.submesh = 0
        self.ignore_input = 0
        self.load_next_texture_coords = 0
        self.skeleton = 0
        self.animationlink = 0

        #保存player.Skeleton 里面存储的骨骼信息
        self.restPose = 0

    def startDocument(self):
        self.mesh = Mesh()
        
    def startElement(self, name, attrs):
        log("read element "+name)
        if name == 'boneassignments':
            #self.boneassignments = {}
            pass

        if name == 'vertexboneassignment':
            log("current submesh is "+str(self.submesh))
            
            vind = int(attrs.get("vertexindex", ""))
            bind = int(attrs.get("boneindex", ""))
            weight = float(attrs.get("weight", ""))

            #共享的骨骼数据 设定子Mesh
            if self.submesh == 0:
                self.submesh = self.mesh

            if bind not in self.submesh.vertexGroup:
                self.submesh.vertexGroup[bind] = []
            self.submesh.vertexGroup[bind].append({"vertexIndex":vind, 
                "boneIndex" :bind, "weight":weight })


        if name == 'skeletonlink':
            self.skeleton = attrs.get("name", '')

        if name == "animationlink":
            self.animationlink = attrs.get("name", '')

        if name == 'sharedgeometry':
            self.submesh = self.mesh

        if name == 'submesh':
            self.submesh = Submesh()
            self.submesh.materialname = attrs.get('material', "")
            self.submesh.indextype = attrs.get('operationtype', "")
            if attrs.get('usesharedvertices') == 'true':
                self.submesh.sharedvertices = 1
        
        if name == 'vertex':
            self.load_next_texture_coords = 1

        if name == 'face' and self.submesh:
            face = (
                int(attrs.get('v1',"")),
                int(attrs.get('v2',"")),
                int(attrs.get('v3',""))
            )
            self.submesh.faces.append(face)
        
        if name == 'position':
            vertex = (
                #Ogre x/y/z --> Blender x/-z/y
                float(attrs.get('x', "")) * IMPORT_SCALE_FACTOR,
                -float(attrs.get('z', "")) * IMPORT_SCALE_FACTOR,
                float(attrs.get('y', "")) * IMPORT_SCALE_FACTOR
            )
            self.submesh.vertices.append(vertex)
               
        if name == 'normal':
            normal = (
                #Ogre x/y/z --> Blender x/-z/y
                float(attrs.get('x', "")),
                -float(attrs.get('z', "")),
                float(attrs.get('y', ""))
            )
            self.submesh.normals.append(normal)
        
        if name == 'texcoord' and self.load_next_texture_coords:
            uv = (
                float(attrs.get('u', "")),
                # flip vertical value, Blender's 0/0 is lower left
                # whereas Ogre's 0/0 is upper left
                1.0 - float(attrs.get('v', ""))
            )
            self.submesh.uvs.append(uv)
            self.load_next_texture_coords = 0

        if name == 'colour_diffuse':
            vc = attrs.get('value', "").split()
            vc[0] = float(vc[0])
            vc[1] = float(vc[1])
            vc[2] = float(vc[2])
            vc[3] = float(vc[3])
            self.submesh.vertexcolours.append(vc)
            
    def endElement(self, name):
        if name == 'submesh':
            self.mesh.submeshes.append(self.submesh)
            self.submesh = 0

'''
设置Blender 中 对象的材质信息
'''
def setMaterial(ob, mat):
    me = ob.data
    me.materials.append(mat)


'''
读取动画的XMl 文件
'''
from xml.dom import minidom
def OpenFile(filename):
    if not os.path.exists(filename):
        return None

    if filename.find('.xml') == -1:
        convert_meshfile(filename)
        filename += '.xml'

    xml_file = open(filename, 'r')
    xml_doc = minidom.parse(xml_file)
    def getEle(name):
        l = xml_doc.getElementsByTagName(name)
        return l[0]
    xml_doc.getElementByTagName = getEle
    xml_file.close()
    return xml_doc


#创建人物的 restpose的骨骼信息
'''
根据骨骼文件名称 skeleton, 读取XML文件，创建基本Pose骨骼
'''
def CreateSkeleton(skeleton, handler):
    global dirname
    if skeleton != 0:
        filename = os.path.join(dirname, skeleton)
        xml_doc = OpenFile(filename)
        if xml_doc != None:
            return CreateBindSkeleton(xml_doc, handler)
        return None


'''
position
angle
rotation
parent
children
flag

translation 世界空间中的 head 位置



TrackData ={
    boneName : {
        time:xx,
        translation:[],
        angle:xx,
        axis:[],
    }
}
'''

'''
根据XMl_DOC 文件，创建骨骼内存数据对象
骨骼位置
旋转
以及父子关系
以及动画关键帧数据
'''
def OGREBonesDic(xmldoc):
    OGRE_Bones = {}
    OGRE_Bone_List = []
    OGRE_Bone_ID = {}

    for bones in xmldoc.getElementsByTagName('bones'):
        for bone in bones.childNodes:
            OGRE_Bone = {}
            if bone.localName == 'bone':
                BoneName = str(bone.getAttributeNode('name').value)
                BoneId = int(bone.getAttributeNode('id').value)
                OGRE_Bone['name'] = BoneName
                OGRE_Bone['id'] = BoneId

                for b in bone.childNodes:
                    if b.localName == 'position':
                        x = float(b.getAttributeNode('x').value)
                        y = -float(b.getAttributeNode('z').value)
                        z = float(b.getAttributeNode('y').value)
                        OGRE_Bone['position'] = [x,y,z]
                    if b.localName == 'rotation':
                        angle = float(b.getAttributeNode('angle').value)
                        axis = b.childNodes[1]
                        axisx = float(axis.getAttributeNode('x').value)
                        axisy = float(axis.getAttributeNode('y').value)
                        axisz = float(axis.getAttributeNode('z').value)

                        #convert ogre coordinate to blender coordinate
                        OGRE_Bone['rotation'] = [axisx, -axisz, axisy]
                        OGRE_Bone['angle'] = angle

                    
                OGRE_Bones[BoneName] = OGRE_Bone
                OGRE_Bone_List.append(OGRE_Bone)
                OGRE_Bone_ID[OGRE_Bone["id"]] = OGRE_Bone


    for bonehierarchy in xmldoc.getElementsByTagName('bonehierarchy'):
        for boneparent in bonehierarchy.childNodes:
            if boneparent.localName == 'boneparent':
                Bone = str(boneparent.getAttributeNode('bone').value)
                Parent = str(boneparent.getAttributeNode('parent').value)
                OGRE_Bones[Bone]['parent'] = Parent

    animations = xmldoc.getElementByTagName("animations")
    animation = animations.getElementsByTagName("animation")[0]

    animationName = str(animation.getAttributeNode("name").value)
    length = float(animation.getAttributeNode("length").value)
    tracks = animation.getElementsByTagName("tracks")[0]
    TrackData = {}
    if length > 0:
        for track in tracks.getElementsByTagName("track"):
            boneName = str(track.getAttributeNode("bone").value)
            TrackData[boneName] = []

            for keyframe in track.getElementsByTagName("keyframes")[0].getElementsByTagName("keyframe"):
                time = float(keyframe.getAttributeNode("time").value)
                translate = keyframe.getElementsByTagName("translate")[0]
                x = float(translate.getAttributeNode("x").value)
                y = float(translate.getAttributeNode("y").value)
                z = float(translate.getAttributeNode("z").value)

                rotate = keyframe.getElementsByTagName("rotate")[0]
                angle = float(rotate.getAttributeNode("angle").value)
                axis = rotate.getElementsByTagName("axis")[0]
                rx = float(axis.getAttributeNode("x").value)
                ry = float(axis.getAttributeNode("y").value)
                
                rz = float(axis.getAttributeNode("z").value)

                #TrackData[boneName].append({"time":time, "translation":[x, -z, y], "angle":angle, "axis":[rx, -rz, ry]})
                #相对于parent 的骨骼空间Z 轴相反
                #局部空间坐标 z -y 
                TrackData[boneName].append({"time":time, "translation":[x, -z, y], "angle":angle, "axis":[rx, -rz, ry]})


    #return OGRE_Bone_List
    return OGRE_Bones, OGRE_Bone_List, OGRE_Bone_ID, TrackData


#骨骼的孩子节点
'''
设置每个骨骼的孩子骨骼列表
'''
def ChildList(BonesData):
  for bone in BonesData.keys():
    childlist = []
    for key in BonesData.keys():
      if BonesData[key].get('parent'):
        parent = BonesData[key]['parent']
        if parent == bone:
            if key.find('tag') != -1:
                childlist.append(BonesData[key])
            else:
                childlist.insert(0, BonesData[key])
    BonesData[bone]['children'] = childlist


#获取所有骨骼的孩子列表缓存起来
#没有孩子节点 或者 有超过1个的孩子节点 的骨骼增加一个Helper骨骼 设置父亲为bone
'''
为无孩子的Joint 增加一个Helper孩子
为多于一个孩子的Joint 增加一个Helper孩子
由于构建一个blender中的父亲骨骼
'''
def HelperBones(BonesData):
    #ChildList(BonesData)
    count = 0
    allHelpBones = {}
    for bone in BonesData.keys():
        if (len(BonesData[bone]['children']) == 0) or (len(BonesData[bone]['children']) > 1):
            HelperBone = {}
            HelperBone['position'] = [0,0.2,0.0]
            HelperBone['parent'] = bone
            HelperBone['rotation'] = [1.0,0.0,0.0]
            HelperBone["angle"] = 0
            HelperBone["name"] = "Helper"+bone
            HelperBone['flag'] = 'helper'
            HelperBone["children"] = []

            #BonesData['Helper'+str(count)] = HelperBone
            allHelpBones['Helper'+bone] = HelperBone
            count+=1
    
    for b in allHelpBones.keys():
        BonesData[b] = allHelpBones[b]



#### 在 0 0 0 位置的骨骼 增加辅助的 0 骨骼到 parent上面
#零长度 骨骼 Pelvis
'''
为在同一个点上的两个 Joint 父子关系 创建Helper 骨骼
'''
def ZeroBones(BonesData):
    allZeroBone = {}
    for bone in BonesData.keys():
        pos = BonesData[bone]['position']
        if (math.sqrt(pos[0]**2+pos[1]**2+pos[2]**2)) == 0:
            ZeroBone = {}
            ZeroBone['position'] = [0,0.2,0.0]
            ZeroBone['rotation'] = [1.0,0.0,0.0]
            ZeroBone["angle"] = 0
            ZeroBone["name"] = "Zero"+bone
            ZeroBone["children"] = []

            if (BonesData[bone].get('parent')):
                ZeroBone['parent'] = BonesData[bone]['parent']
            ZeroBone['flag'] = 'zerobone'
            #BonesData['Zero'+bone] = ZeroBone
            allZeroBone['Zero'+bone] = ZeroBone
            if (BonesData[bone].get('parent')):
                BonesData[BonesData[bone]['parent']]['children'].append('Zero'+bone)

    for k in allZeroBone.keys():
        BonesData[k] = allZeroBone[k]

'''
计算骨骼长度 ZeroBones 中使用
'''
def CalcBoneLength(vec):
    return math.sqrt(vec[0]**2+vec[1]**2+vec[2]**2)


'''
通过创建空的正方体对象来模拟joint 最后连接这些正方体对象得到骨骼
位置偏移 和 旋转 都是相对于父亲的 局部空间的变换

创建空的正方体，用于计算每个骨骼的blender空间中的位置

'''
#计算每个joint的旋转矩阵 世界坐标中的旋转矩阵
#创建空物体 来摆出pose 接着计算每个骨骼的相对位置
def CreateEmptys(BonesDic, delete=True):
    if bpy.context.object != None:
        bpy.ops.object.mode_set(mode="OBJECT")
    bpy.ops.object.select_all(action="DESELECT")

    #对象存在 但是被unlink 了 可以重新link回来
    if bpy.data.objects.get("Cube"):
        modelCube = bpy.data.objects["Cube"]
        if bpy.context.scene.objects.find("Cube") == -1:
            bpy.context.scene.objects.link(modelCube)
            log("relink cube")
    else:
        bpy.ops.mesh.primitive_cube_add()
        modelCube = bpy.data.objects["Cube"]
        for k in modelCube.data.vertices.values():
            k.co *= 0.1

    modelCube.location = (4, 0, 0)
    modelCube.select = True
    modelCube.name = "Cube"

    bpy.context.scene.update()

    '''
    创建骨架空物体
    '''
    '''
    检查对应骨骼是否存在
    '''
    #不存在才创建
    if bpy.data.objects.get("root") == None:
        for bone in BonesDic.keys():
            #bpy.ops.mesh.primitive_cube_add()
            bpy.ops.object.select_all(action="DESELECT")
            modelCube.select = True
            modelCube.name = "Cube"

            bpy.ops.object.duplicate()

            obj = bpy.data.objects["Cube.001"]
            obj.name = bone 
            log("create Cube: "+obj.name)
    else:
        for bone in BonesDic.keys():
            if not bpy.data.objects.get(bone):
                bpy.ops.object.select_all(action="DESELECT")
                modelCube.select = True
                modelCube.name = "Cube"

                bpy.ops.object.duplicate()

                obj = bpy.data.objects["Cube.001"]
                obj.name = bone 
                log("create Cube: "+obj.name)



    '''
    创建父子关系
    '''
    for bone in BonesDic.keys():
        if BonesDic[bone].get('parent'): 
            if bpy.data.objects.get(bone) != None:
                Parent = bpy.data.objects[BonesDic[bone].get('parent')]
                obj = bpy.data.objects[bone]
                obj.parent = Parent


    '''
    设定空物体的位置和旋转 相对于父物体
    helper 骨骼不用调整数据
    '''
    for bone in BonesDic.keys():
        #if BonesDic[bone].get("flag") == None:
        #if bpy.data.objects.get(bone) != None:
        obj = bpy.data.objects[bone]
        rot = BonesDic[bone]['rotation']
        angle = BonesDic[bone]['angle']
        loc = BonesDic[bone]['position']
        euler = mathutils.Matrix.Rotation(angle, 3, rot).to_euler()
        obj.location = loc
        obj.rotation_euler = euler

    bpy.ops.object.select_all(action="DESELECT")
    bpy.context.scene.update()

    '''
    保存空物体的相对于父亲物体的 matrix_local 和 转化到世界空间的
    '''
    for bone in BonesDic.keys():
        #if bpy.data.objects.get(bone) != None:
        obj = bpy.data.objects[bone]

        #rotmatAS = obj.matrix_world.to_quaternion()
        translation = obj.matrix_world.to_translation()
        log("obj matrix update "+obj.name+" "+str(translation))
        #BonesDic[bone]['rotmatAS'] = rotmatAS.to_matrix()
        BonesDic[bone]["translation"] = translation
        BonesDic[bone]["matrix_local"] = obj.matrix_local.copy()
        BonesDic[bone]["matrix_world"] = obj.matrix_world.copy()

    '''
    隐藏空物体joint
    '''
    for bone in BonesDic.keys():
        obj = bpy.data.objects[bone]
        obj.hide = True


'''
将对象从blender中删除 包括对象的孩子 孙子，递归删除
'''
def Unlink(obj):
    if obj == None:
        return
    ok = False
    try:
        bpy.context.scene.objects.unlink(obj)
        ok = True
    except:
        pass
    if ok:
        for c in obj.children:
            Unlink(c)


'''
隐藏对象整体
'''
def togHide(r):
    r.hide = not r.hide
    for c in r.children:
        togHide(c)

import mathutils


'''
根据读取的动画数据 创建每一帧的骨骼动画

针对动画骨架Armature2 制作其对应的 pose动画 只有骨架动画
'''
def CreatePoseAnimation(BonesDic, BonesList, BoneID, TrackData, BonesData, handler):
    #TrackData[boneName].append({time=time, translation={x, -z, y}, angle=angle, axis={rx, -rz, ry}})
    #每个joint 相对于 初始骨骼位置的偏移 从joint 位置 旋转 计算 旋转 rotation 和 scale属性
    #每个joint 影响其所在的骨骼 以及每个子骨骼的位置
    #调整 动画中的Empty物体的位置 然后生成一个新的 骨骼位置 

    #调整一个joint的位置 parent和children 相关联的都会修改矩阵 重新计算矩阵在 edit mode 下
    #然后计算edit mode下旋转结果 重新计算这组骨骼的 qua 和 scale信息
    #然后设置 一个关键帧在pose mode下面 
    bpy.ops.object.mode_set(mode="OBJECT")
    bpy.ops.object.select_all(action="DESELECT")

    amt_obj = bpy.data.objects["Armature"]
    amt_data = amt_obj.data
    amt_obj.select = True
    bpy.context.scene.objects.active = amt_obj
    bpy.ops.object.mode_set(mode="POSE")
    bpy.ops.pose.select_all(action="DESELECT")
    
    maxFrame = 0

    '''
    遍历每一根动画骨骼
    遍历每一帧 
    设置骨骼的位置
    '''
    restPoseEdit = handler.restPose
    log("restPoseBone is "+str(restPoseEdit))
    for boneName in TrackData.keys():
        tracks = TrackData[boneName]
        count = 0
        bone = BonesDic[boneName]
        restBone = restPoseEdit[boneName]
        rp = Vector(restBone["position"])
        bp = Vector(bone["position"])
        poseBone = amt_obj.pose.bones[boneName]
        
        normalBone = amt_data.bones[boneName]

        quaRest = Matrix.Rotation(restBone["angle"], 3, restBone["rotation"]).to_quaternion()
        quaAni = Matrix.Rotation(bone["angle"], 3, bone["rotation"]).to_quaternion()
        
        normalBone.select = True
        for frame in tracks:
            time = frame["time"]
            fnum = int(round(time*60))
            maxFrame = max(maxFrame, fnum)

            translation = Vector(frame["translation"])
            angle = frame["angle"]
            axis = frame["axis"]

            FrameTranslate = translation
            FrameQua = Matrix.Rotation(angle, 3, axis).to_quaternion()

            #poseBone.select = True
            #需要操作对应的 bones 选择不能操作pose选择

            bpy.context.scene.frame_set(fnum)
            poseBone.location = bp-rp+FrameTranslate
            poseBone.rotation_mode = "QUATERNION"
            #比较restPose 和 动作状态下的骨骼旋转
            #poseBone.rotation_quaternion = FrameQua*quaAni*quaRest.inverted() #quaRest.rotation_difference(quaAni)

            poseBone.rotation_quaternion = quaAni*FrameQua *quaRest.inverted() #quaRest.rotation_difference(quaAni)


            bpy.ops.anim.keyframe_insert_menu(type="LocRotScale")
            #poseBone.select = False

        normalBone.select = False

    bpy.data.scenes["Scene"].frame_end = maxFrame-1

    return
          



'''
建立动画骨骼 基础形态
接着调用其他函数 创建 每一帧骨骼动画
'''
#创建一个动画的初始的 pose状态 调整armature的骨骼位置

#进入pose mode 调整每一个每个骨骼的head 和 tail位置
#旋转子骨骼到目标位置 的一个旋转方向 location rotation scale 沿着骨骼的轴方向的
#head ---> tail 之间的一个旋转方向 变化 从原方向 到新方向之间的旋转变化
import math
def CreateAnimationPose(animationlink, handler):
    global dirname
    if animationlink != 0 and animationlink != None:
        filename = os.path.join(dirname, animationlink)
        xml_doc = OpenFile(filename)
        if xml_doc == None:
            return False

        #得到动画pose中每个骨骼的变换矩阵
        #分析xml文件得到 攻击动作的初始 骨骼位置 pose
        #60frame/s int(time*60) = frame
        '''
        解析动画骨骼初始位置 数据
        创建每个骨骼的孩子列表
        创建帮助性骨骼 用于无孩子的Joint 增加一个孩子构成一个骨骼，多于一个孩子的骨骼，增加一个 Helper 孩子用于创建骨骼，其它孩子为正常的骨骼
        仅有一个孩子的Joint 可以和孩子连接起来构成一个骨骼

        对于0长度的两个Joint 需要创建辅助性骨骼避免掉 长度0
        '''
        BonesDic, BonesList, BoneID, TrackData = OGREBonesDic(xml_doc)
        #BonesData = []
        ChildList(BonesDic)
        HelperBones(BonesDic)
        ZeroBones(BonesDic)
        #创建空物体来 计算骨骼的坐标位置
        #保存攻击的joint 重新计算每个骨骼的位置相对变化
        '''
        计算每个joint的 matrix_world 状态变化 设置对应骨骼的状态
        创建空的Cube 来调整每个骨骼的初始位置
        '''
        CreateEmptys(BonesDic, False)
        
        #对比restPose Bone 和 动画 骨骼的 head tail roll 来计算 pose下的rotation
        #先制作旋转 再做roll旋转
        #将 目标骨骼方向向量转化到 rest骨骼的空间中
        #计算 (0, 1, 0) 方向和 转化方向之间的旋转四元式
        #设置pose 骨骼的rotation_quaternion旋转数据
        

        if bpy.context.object != None:
            bpy.ops.object.mode_set(mode="OBJECT")
            bpy.context.object.select = False
            bpy.ops.object.select_all(action="DESELECT")

        
        amt_obj = bpy.data.objects["Armature"]
        amt_data = amt_obj.data

        #调整 基础骨骼 pose骨骼的 位置 缩放 旋转 
        bpy.ops.object.select_all(action="DESELECT")
        amt_obj.select = True
        bpy.context.scene.objects.active = amt_obj

        bpy.ops.object.mode_set(mode="POSE")
        bpy.ops.pose.select_all(action="SELECT")

        '''
        插入动画第一帧为Pose 形态
        '''
        bpy.context.scene.frame_set(0)
        bpy.ops.anim.keyframe_insert_menu(type="LocRotScale")

        BonesData = None
        CreatePoseAnimation(BonesDic, BonesList, BoneID, TrackData, BonesData, handler)
        return True



BoneID2Name = {}

#create blender armature submesh multiple mesh  use shared vertex or not share
#convert ogre joint to bones
#建立绑定位置的 骨骼位置信息  pose mode下面可以调整微调
'''
创建Mesh.xml 中连接的Skeleton 骨骼文件的默认骨骼形态
FIX: 清理上个模型的动画数据
'''
def CreateBindSkeleton(xmldoc, handler):
    if GetAmt() != None:
        log("Armature exist just return")
        return

    BonesDic, BonesList, BoneID, TrackData = OGREBonesDic(xmldoc)
    global BoneID2Name
    BoneID2Name = BoneID
    #BonesData = BonesDic
    BonesData = []
    ChildList(BonesDic)
    HelperBones(BonesDic)
    ZeroBones(BonesDic)
    CreateEmptys(BonesDic)
    #稳定
    handler.restPose = BonesDic

    
    log("Create New Armature")    
    bpy.ops.object.add(type="ARMATURE", enter_editmode=True)
    amt_obj = bpy.context.object
    amt_obj.location = Vector((0, 0, 0))
    amt_obj.show_x_ray = True

    amt_data = amt_obj.data
    amt_data.show_axes = True

    #joint to bone root-> some bone
    #root is an empty Bone  joint first Bone is parent
    bpy.ops.armature.select_all(action="DESELECT")

    log("initial Bone")
    for k in BonesDic.keys():
        boneData = BonesDic[k]
        bone = amt_data.edit_bones.new(boneData['name'])

        bone.head = boneData["translation"]
        children = boneData["children"]
        if len(children) == 1:
            childname = children[0]["name"]
            vectailadd = CalcBoneLength(children[0]["position"])
        else:
            vectailadd = 0.2
        
        #qua = boneData["matrix_world"].to_3x3().to_quaternion()
        #设定骨骼的矩阵为 joint的矩阵
        '''
        骨骼使用parent的旋转矩阵 来计算 location 位置
        但是应该使用本地的矩阵来计算 rotation数值
        '''
        bone.tail = bone.head + Vector((0, vectailadd, 0))
        if boneData.get("parent") != None:
            parent = BonesDic[boneData["parent"]]
            rotMat = parent["matrix_world"].to_3x3().to_4x4()
            rotMat[0][3] = bone.head[0]
            rotMat[1][3] = bone.head[1]
            rotMat[2][3] = bone.head[2]
            bone.matrix = rotMat
        else:
            #如果没有父亲则 旋转为 单位矩阵
            pass
        
        #设定roll值 参考Edit mode Y 轴的旋转方向
        #joint  相对于父亲的旋转矩阵 和偏移矩阵
        #matrix_world 本地 0 0 转化到世界坐标 roll值是使用世界坐标计算的
        #世界坐标 0 0 位置物体 移动到 目标的位置 并且旋转  平移世界物体的矩阵 
        #计算joint沿着 Y 方向的旋转值

    for bone in amt_data.edit_bones:
        if BonesDic[bone.name].get("parent") != None:
            bone.parent = amt_data.edit_bones[BonesDic[bone.name]["parent"]]
    
    bpy.ops.armature.select_all(action="DESELECT")
    for bone in amt_data.edit_bones:
        if BonesDic[bone.name].get("flag") != None:
            bone.select = True


    bpy.ops.armature.delete()
    bpy.context.scene.update()
    return


#从每个submesh 里面抽取出vertexGroup的数据
#建立一个 vertexGroup
#将对应定点放到group里面
#group 按照数字名称来分组
#def CreateVertexGroup(name, mesh):

#分析完一个子mesh的时候 子物体就添加一个顶点group
from mathutils import Color

'''
根据OgreMeshSaxHandler 生成blender中Mesh 对象
'''
def CreateBlenderMesh(name, mesh, materials):
    if bpy.context.object != None:
        bpy.ops.object.mode_set(mode="OBJECT")
    bpy.ops.object.select_all(action="DESELECT")


    # dict matname:blender material
    bmaterials = {}
    bmat_idx = -1

    log("Mesh with %d shared vertices." % len(mesh.vertices))
    vertex_count = len(mesh.vertices)
    
    shareVert = mesh.vertices
    shareNormal = mesh.normals
    shareUV = mesh.uvs
    shareColour = mesh.vertexcolours

    submesh_count = len(mesh.submeshes)
    vertex_offset = 0
    faces = []

    #bpy.context.active_object = None
    
    log("read len submesh "+str(submesh_count))
    for j in range(0, submesh_count): 
        submesh = mesh.submeshes[j]
        log("createMesh "+submesh.materialname)

        vert = submesh.vertices
        faces = submesh.faces
        uvs = submesh.uvs
        vertexGroup = submesh.vertexGroup
        vertexcolours = submesh.vertexcolours

        if submesh.sharedvertices == 1:
            vert = shareVert
            uvs = shareUV
            vertexGroup = mesh.vertexGroup
            vertexcolours = shareColour

        objmesh = bpy.data.meshes.new("mesh"+str(j))

        obj = bpy.data.objects.new("obj"+str(j), objmesh)
        obj.location = bpy.context.scene.cursor_location
        bpy.context.scene.objects.link(obj)

        objmesh.from_pydata(vert, [], faces)
        objmesh.update(calc_edges=True)

        obj.select = True
        bpy.context.scene.objects.active = obj

        bpy.ops.object.mode_set(mode="EDIT")
        #if bpy.context.mode == 'EDIT_MESH':
        #for f in bm.faces:

        obj = bpy.context.active_object
        me = obj.data
        bm = bmesh.from_edit_mesh(me)

        uv_layer = bm.loops.layers.uv.verify()
        bm.faces.layers.tex.verify()

        colLayer = None
        if len(vertexcolours) > 0:
            colLayer = bm.loops.layers.color.verify()

        #设置loop 循环上面的每个定点的uv 坐标获得定点的编号来索引到对应的uv坐标
        for f in bm.faces:
            for l in f.loops:
                luv = l[uv_layer]
                ind = l.vert.index
                luv.uv = Vector(uvs[ind])
                if colLayer:
                    l[colLayer] = Color(vertexcolours[ind][:3])


        bmesh.update_edit_mesh(me)
        me.update()

        bpy.ops.object.mode_set(mode="OBJECT")

        #检测骨骼编号 和 对应的骨骼名称
        log("skeleton ID")
        allID = set(BoneID2Name.keys())
        useID = set(submesh.vertexGroup.keys())

        diffID = useID-allID
        
        for k in diffID:
            log("lostID "+str(k))

        log("all Lost ID "+str(len(allID)))
        for k in allID:
            log("allID "+str(k)+" "+str(BoneID2Name[k]))


        if materials.get(submesh.materialname) != None:
            omat = materials[submesh.materialname]
            bmat = 0
            if not bmaterials.get(submesh.materialname):
                bmat = create_blender_material(omat)
                bmaterials[submesh.materialname] = bmat
            else:
                bmat = bmaterials[submesh.materialname]

            setMaterial(obj, bmat)

        #lost some bones don't create vertex group
        if len(diffID) == 0:            
            #初始化顶点组
            #以骨骼快速分析骨骼名称得到实际骨骼名称
            #OGREBonesDic

            #尝试将一个 joint 上面的定点权重/2 平分到相邻的两个骨骼上面即可
            #也就是一个joint vertexGroup 对应两个 bone的 vertexGroup
            #分别是 tail 和 别的骨骼的head
            #如果这个有多个child 则 平分权重到 多个child+parent上面即可

            for k in vertexGroup:
                log("vertexGroup is read"+str(k))
                parentNode = BoneID2Name[k]
                #有孩子骨骼则权重分配到孩子身上 没有则自己吞掉
                group = obj.vertex_groups.new(parentNode["name"])
                for v in vertexGroup[k]:                    
                    group.add([v["vertexIndex"]], v["weight"], 'REPLACE')

        log("after create vertexGroup")

        

        #设置模型材质

    bpy.ops.object.join()

    return bpy.context.object

'''
将Mesh 转化成.xml 文件
'''
def convert_meshfile(filename):
    log("convert file "+filename)
    if not os.path.exists(filename):
        return
    if IMPORT_OGREXMLCONVERTER != '':
        commandline = IMPORT_OGREXMLCONVERTER +' -log /Users/liyong/err.log '+ ' "' + filename + '"' + ' "'+ filename + '.xml' + '"'
        log("executing %s" % commandline)
        log(os.path.abspath('.'))
        status = os.system(commandline)
        log('status '+str(status))
        log("done.")


'''
收集某个目录里面的 .material 文件的材质信息
'''
def collect_materials(dirname):
    # preparing some patterns
    #    to collect the material name
    matname_pattern = re.compile('^\s*material\s+(.*?)\s*$')
    #    to collect the texture name
    texname_pattern = re.compile('^\s*texture\s+(.*?)\s*$')
    #    to collect the diffuse colour
    diffuse_alpha_pattern = re.compile(\
            '^\s*diffuse\s+([^\s]+?)\s+([^\s]+?)\s+([^\s]+?)\s+([^\s]+).*$')
    diffuse_pattern = re.compile(\
            '^\s*diffuse\s+([^\s]+?)\s+([^\s]+?)\s+([^\s]+).*$')
    #    to collect the specular colour
    specular_pattern = re.compile(\
            '^\s*specular\s+([^\s]+?)\s+([^\s]+?)\s+([^\s]+).*$')

    ambient_pattern = re.compile(
            '^\s*ambient\s+([^\s]+?)\s+([^\s]+?)\s+([^\s]+).*$')
    
    # the dictionary where to put the materials
    materials = {}

    # for all lines in all material files..
    material_files1 = glob.glob(dirname + '/*.material')
    material_files2 = glob.glob(dirname + '/*.MATERIAL')
    material_files = material_files1+material_files2
    for filename in material_files:
        f = open(filename, 'r')
        line_number = 0
        material = 0
        matContent = ''
        inMat = False
        for line in f:
            try:
                line_number = line_number + 1
                dlog("line to be matched: %s" % line)
                
                #m = matname_pattern.match(line)
                mat_name = matname_pattern.findall(line)

                if len(mat_name) > 0:
                    if material != 0:
                        log("oldMat is "+material.name)
                        log("set Material Content "+matContent)
                        material.matFileCon = matContent
                        matContent = ''

                    material = Material(mat_name[0])
                    matContent = line
                    inMat = True

                    materials[material.name] = material
                    vlog("parsing material %s" % mat_name[0])
                else:
                    matContent += line

                #m = texname_pattern.match(line)
                tex_name = texname_pattern.findall(line)
                # load only the first texture unit's texture
                # TODO change to use the first one using the first uv set
                if len(tex_name) > 0 and not material.texname:
                #if m and not material.texname:
                    material.oldTexName = tex_name[0]
                    material.texname = dirname + '/' + tex_name[0]

                m = diffuse_alpha_pattern.match(line)
                if not m:
                    m = diffuse_pattern.match(line)
                if m:
                    vlog("    parsing diffuse..")
                    groups = m.groups()
                    r = float(groups[0])
                    g = float(groups[1])
                    b = float(groups[2])
                    #TODO: alpha still untested
                    if len(groups) > 3:
                        a = float(groups[3])
                    else:
                        a = 1.0
                    
                    material.diffuse = (r, g, b, a)
                    vlog("   diffuse: %s" % str(material.diffuse))
                m = specular_pattern.match(line)
                if m:
                    vlog("    parsing specular..")
                    groups = m.groups()
                    r = float(groups[0])
                    g = float(groups[1])
                    b = float(groups[2])
                    
                    material.specular = (r, g, b, 1.0)
                    vlog("   specular: %s" % str(material.specular))

            except Exception as e:
                log("    error parsing material %s in %s on line % d: " % \
                    (material.name, filename, line_number))
                log("        exception: %s" % str(e))

        if material != 0:
            log("set LastMat matContent "+material.name)
            log("last matContent "+matContent)
            material.matFileCon = matContent
            log("this mat file con "+material.matFileCon)
    return materials
            

def create_blender_material(omat):
    mat = bpy.data.materials.new(omat.name)
    mat.diffuse_color = omat.diffuse[:3]
    mat.diffuse_shader = 'LAMBERT'
    mat.diffuse_intensity = 1.0
    mat.specular_color = omat.specular[:3]
    mat.specular_shader = 'COOKTORR'
    mat.specular_intensity = 1.0
    mat.alpha = omat.diffuse[3]
    mat.ambient = 1

    img = omat.getTexture()
    log("getTexture is "+str(img))
    if img:
        cTex = bpy.data.textures.new(omat.texname, type="IMAGE")
        cTex.image = img

        mtex = mat.texture_slots.add()
        mtex.texture = cTex
        mtex.texture_coords = "UV"
        mtex.use_map_color_diffuse = True
        #mtex.use_map_color_emission = True
        #mtex.emission_color_factor = 0.5
        #mtex.use_map_density = True
        mtex.mapping = "FLAT"

    return mat





dirname = None
basename = None
allAnimations = []

skePat = re.compile("\w+\.skeleton")
xmlFile = None
materials = None

'''
为每个动画生成对应的FBX文件
mage@idle.fbx
'''
def GenFbxFile(aniFile, handler, export=True):
    log("GenFbxFile "+str(aniFile))

    bpy.ops.object.select_all(action="DESELECT")

    '''
    重新连接骨架
    '''
    amt = bpy.data.objects.get("Armature")
    if amt != None:
        if amt != None and bpy.context.scene.objects.find("Armature") == -1:
            bpy.context.scene.objects.link(amt)        
        bpy.context.scene.objects.active = amt
        amt.select = True

    '''
    获取amt 骨架，接着根据AnimationFile 内容生成骨骼Pose信息
    '''
    okFile = CreateAnimationPose(aniFile, handler)

    '''
    清理root 等虚拟物体 组成的骨架对象
    '''
    if bpy.data.objects.get("root") != None:
        if bpy.context.scene.objects.get('root') != None:
            Unlink(bpy.data.objects["root"])
        Unlink(bpy.data.objects["Cube"])
    

    bpy.ops.object.mode_set(mode="OBJECT")
    
    '''
    清空辅助的骨骼 mesh
    '''
    clearScene() 
    '''
    是否导出Fbx 并且正确读入了动画xml文件
    是否需要动画XML 文件呢
    '''
    log("export And OkFile "+str(export)+" "+str(okFile))
    if export: #and okFile:
        global dirname
        oldDirName = dirname
        fbxDirName = os.path.join(dirname, "fbx")
        matDirName = os.path.join(fbxDirName, 'mat')
        if not os.path.exists(fbxDirName):
            os.mkdir(fbxDirName)
        if not os.path.exists(matDirName):
            os.mkdir(matDirName)
        global basename
        log("base name is "+basename)
        if aniFile != None:
            aniName = str(aniFile).replace(".skeleton", "")
        else:
            aniName = ''
        basename = basename.lower()
        objName = basename.replace(".animation", "").replace(".MESH.xml", "").replace(".mesh.xml", "")
        if aniName != '':
            fbxName = os.path.join(fbxDirName, objName+"@"+aniName+".fbx")
        else:
            fbxName = os.path.join(fbxDirName, objName+".fbx")

        log("export FbxFileName "+fbxName)
        bpy.ops.export_scene.fbx(filepath=fbxName, use_anim_action_all=False, bake_anim_use_nla_strips=False, bake_anim_use_all_actions=False, axis_forward='Z')
        #bpy.ops.export_scene.fbx(filepath=fbxName)

        mesh = handler.mesh
        submesh_count = len(mesh.submeshes)
        for j in range(0, submesh_count):
            submesh = mesh.submeshes[j]
            ogre_mat = materials.get(submesh.materialname)
            if ogre_mat != None:
                log("save Texture file And Material %s" % ogre_mat.oldTexName)
                newMatName = submesh.materialname.replace("/", "_")+'.mat'

                matFile = os.path.join(matDirName, newMatName)

                texName = ogre_mat.oldTexName.replace('dds', 'png')
                log("")
                p2 = os.path.join(fbxDirName, texName)
                p1 = os.path.join(oldDirName, texName)

                log("save MatFile: "+matFile)
                log("save Mat Content is: "+ogre_mat.matFileCon)
                matF = open(matFile, 'w')
                matF.write(ogre_mat.matFileCon)
                matF.close()
                
                log(p1+"  "+p2)
                cmd = 'cp %s %s' % (p1 ,  p2)
                log("copy texture file: "+cmd)
                os.system(cmd)

        log("import completed.")


'''
执行顺序
fileselection_callback
GenFbxFile
CreateAnimationPose
    OGREBonesDic
    ChildList
    HelperBones
    ZeroBones
    CreateEmptys
    CreatePoseAnimation
'''
   
  
import subprocess  
def fileselection_callback(filename, clearMesh):

    '''
    读取mesh 文件，如果不是xml格式则调用 ogre 工具转化
    '''
    log("Reading mesh file %s..." % filename)
    filename = os.path.expanduser(filename)

    # is this a mesh file instead of an xml file?
    if (filename.lower().find('.xml') == -1):
        # No. Use the xml converter to fix this
        log("No mesh.xml file. Trying to convert it from binary mesh format.")
        convert_meshfile(filename)
        filename += '.xml'

    global dirname
    global basename
    dirname = os.path.dirname(filename)
    basename = os.path.basename(filename)

    '''
    读取Animation文件, 如果存在则存储下animation动画列表
    '''
    global allAnimations    
    aniFileName = filename.replace("MESH.xml", "animation").replace("mesh.xml", "animation").replace("Mesh.xml", "animation")
    log("readANiFileName "+str(aniFileName))
    if os.path.exists(aniFileName):
        proc = subprocess.Popen(["file", aniFileName], stdout=subprocess.PIPE)
        (out, err) = proc.communicate()
        out = out.decode('utf8')
        if out.find("UTF-16") != -1:
            aniCon = codecs.open(aniFileName, encoding='utf16', mode='rb').read()
        else:
            aniCon = codecs.open(aniFileName, mode='rb').read()
        allAnimations = skePat.findall(aniCon)
    else:
        #No Animation File
        allAnimations = []

    log("aniFileName "+aniFileName)
    log("Gather all ANimation "+str(allAnimations))
    
    '''
    读取当前目录的材质文件，收集所有的材质信息
    '''
    # parse material files and make up a dictionary: {mat_name:material, ..}
    global materials
    materials = collect_materials(dirname)

    #create materials
    
    # prepare the SAX parser and parse the file using our own content handler
    '''
    读取Mesh.xml 文件， 将模型信息存储到OgreMeshSaxHandler 中
    '''
    xmlFile = open(filename, 'r')
    #解析Mesh 和 Bone文件
    parser = xml.sax.make_parser()   
    handler = OgreMeshSaxHandler()
    parser.setContentHandler(handler)
    parser.parse(xmlFile)
    
    # create the mesh from the parsed data and link it to a fresh object
    meshname = basename[0:basename.lower().find('.mesh.xml')]

    #生成骨骼
    '''
    根据OgreMeshSaxHandler 如果Mesh文件中存在骨骼，则创建一个骨骼对象
    '''
    CreateSkeleton(handler.skeleton, handler)
    
    #生成蒙皮 和 顶点组
    '''
    根据OgreMeshSaxHandler 构建蒙皮 Mesh对象 设置材质等信息
    '''
    obj = CreateBlenderMesh(meshname, handler.mesh, materials)
    bpy.context.scene.update()


    '''
    获得骨骼对象，如果allAnimations >0 则表示需要生成骨骼动画调用GenFbxFile 生成动画
    否则值生成普通的仅包含Mesh的fbx 文件
    '''

    amt = GetAmt()
    bpy.ops.object.select_all(action="DESELECT")
    if amt != None:
        bpy.context.scene.objects.active = amt
        obj.select = True
        amt.select = True
        bpy.ops.object.parent_set(type="ARMATURE")

    if handler.animationlink != 0:
        GenFbxFile(handler.animationlink, handler, False)
    elif len(allAnimations) == 0:
        GenFbxFile(None, handler)
    else:
        for a in allAnimations:
            GenFbxFile(a, handler)
            
            log("Clear Animation Frame "+a)
            #测试 导入mage fidget 动画
            #break 
            #2.74 bug 调用这个会导致创建一份新的Action
            
            bpy.ops.anim.keyframe_clear_v3d()
            #bpy.context.scene.objects.active.animation_data_clear()
            
            #如何只导出当前使用的AnimationData 里面的actin而不是所有的action呢？
            #bpy.ops.poselib.unlink()
            
            #测试一个动画的生成
            #break
    
    #clear all scene Object
    if clearMesh:
        clearAll()

import random
oldId = 0
rand = random.Random()
def GetAmt():
    amt = bpy.data.objects.get("Armature")
    #这个骨骼已经被删除了 是上一个模型的
    if bpy.context.scene.objects.find('Armature') == -1:
        if amt != None:
            global rand
            global oldId
            amt.name = "Armature_"+str(oldId)+"_"+str(rand.randint(1, 10000))
            oldId += 1
        return None
    return amt


'''
清理场景中所有的 虚拟骨骼对象
不要清除掉Mesh 对象
'''
def clearScene():
    #global toggle
    scn = bpy.context.scene
    log("clearScene ")
    
    if bpy.context.object != None:
        bpy.ops.object.mode_set(mode="OBJECT")
    for ob in scn.objects:
        if ob.type in ["MESH", "CURVE", "TEXT"]:
            if ob.name.find('obj') == -1:#don't delete obj mesh
                scn.objects.active = ob    
                scn.objects.unlink(ob)
            del ob
    return scn


'''
连同模型Mesh 一起清理，为导入新的模型做准备
连通Armature 一起清理 为下一个动画模型做准备
'''
def clearAll():
    scn = bpy.context.scene
    log("clear ALl Scene ")
    
    if bpy.context.object != None:
        bpy.ops.object.mode_set(mode="OBJECT")
    for ob in scn.objects:
        #if ob.type in ["MESH", "CURVE", "TEXT"]:
        #if ob.name.find('obj') == -1:#don't delete obj mesh
        scn.objects.active = ob    
        scn.objects.unlink(ob)
        del ob
    return scn


from bpy.props import *
from bpy_extras.io_utils import (ExportHelper,
                                 path_reference_mode,
                                 axis_conversion,
                                 )

class IMPORT_OT_OGRE(bpy.types.Operator):
    bl_idname = "import_scene.ogre_mesh"
    bl_description = 'Import from mesh file format (.mesh)'
    bl_label = "Import mesh" +' v.'+ __version__
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_options = {'UNDO'}


    filepath = StringProperty(
            subtype='FILE_PATH',
            )
    clearMesh = BoolProperty(
            default=False,
        )
    def draw(self, context):
        layout0 = self.layout
        layout = layout0.box()
        col = layout.column()
        
         
    def execute(self, context):
        
        fileselection_callback(self.filepath, self.clearMesh)
        return {'FINISHED'}

    def invoke(self, context, event):
        wm = context.window_manager
        wm.fileselect_add(self)
        return {'RUNNING_MODAL'}



def menu_func(self, context):
    self.layout.operator(IMPORT_OT_OGRE.bl_idname, text="ogre (.mesh)")


def register():
    bpy.utils.register_module(__name__)
    bpy.types.INFO_MT_file_import.append(menu_func)

def unregister():
    bpy.utils.unregister_module(__name__)

    bpy.types.INFO_MT_file_import.remove(menu_func)

if __name__ == "__main__":
    register()

